package com.chlitina.store.modules.cash.service;

import java.util.HashMap;
import java.util.List;

import org.hibernate.FetchMode;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.chlitina.store.common.mapper.JsonMapper;
import com.chlitina.store.common.service.BaseService;
import com.chlitina.store.common.utils.DateUtils;
import com.chlitina.store.common.utils.StoreCareUtils;
import com.chlitina.store.common.utils.StoreProductUtils;
import com.chlitina.store.modules.base.dao.StoreProductDao;
import com.chlitina.store.modules.base.entity.StoreCardTemplateProduct;
import com.chlitina.store.modules.base.entity.StoreCardTemplateProductDetail;
import com.chlitina.store.modules.base.entity.StoreCare;
import com.chlitina.store.modules.base.entity.StoreProduct;
import com.chlitina.store.modules.base.service.CustomerEmployeeRelationshipService;
import com.chlitina.store.modules.base.service.StoreCareService;
import com.chlitina.store.modules.cash.dao.StoreCardAllDao;
import com.chlitina.store.modules.cash.dao.StoreCardDurationDao;
import com.chlitina.store.modules.cash.dao.StoreCardProductDao;
import com.chlitina.store.modules.cash.dao.StoreCardTimesDao;
import com.chlitina.store.modules.cash.dao.StoreConsumeBuyProductDao;
import com.chlitina.store.modules.cash.dao.StoreConsumeDao;
import com.chlitina.store.modules.cash.dao.StoreConsumeDebtDao;
import com.chlitina.store.modules.cash.dao.StoreConsumeDoCareDao;
import com.chlitina.store.modules.cash.dao.StoreConsumeNewCardDao;
import com.chlitina.store.modules.cash.dao.StoreConsumeRechargeCardDao;
import com.chlitina.store.modules.cash.entity.StoreCardAll;
import com.chlitina.store.modules.cash.entity.StoreCardDuration;
import com.chlitina.store.modules.cash.entity.StoreCardProduct;
import com.chlitina.store.modules.cash.entity.StoreCardTimes;
import com.chlitina.store.modules.cash.entity.StoreConsume;
import com.chlitina.store.modules.cash.entity.StoreConsumeBuyProduct;
import com.chlitina.store.modules.cash.entity.StoreConsumeDebt;
import com.chlitina.store.modules.cash.entity.StoreConsumeDoCare;
import com.chlitina.store.modules.cash.entity.StoreConsumeNewCard;
import com.chlitina.store.modules.cash.entity.StoreConsumeRechargeCard;
import com.chlitina.store.modules.cash.model.AllCardPayment;
import com.chlitina.store.modules.cash.model.AllCardPaymentDetail;
import com.chlitina.store.modules.cash.model.CardCart;
import com.chlitina.store.modules.cash.model.CardPayment;
import com.chlitina.store.modules.cash.model.Cards;
import com.chlitina.store.modules.cash.model.CarePayment;
import com.chlitina.store.modules.cash.model.DurationCardPayment;
import com.chlitina.store.modules.cash.model.GiftCart;
import com.chlitina.store.modules.cash.model.Member;
import com.chlitina.store.modules.cash.model.MemberConsumeDetail;
import com.chlitina.store.modules.cash.model.MemberPayResult;
import com.chlitina.store.modules.cash.model.MemberShoppingCart;
import com.chlitina.store.modules.cash.model.NewCards;
import com.chlitina.store.modules.cash.model.ProductCardPayment;
import com.chlitina.store.modules.cash.model.ProductCardPaymentDetail;
import com.chlitina.store.modules.cash.model.ProductPayment;
import com.chlitina.store.modules.cash.model.ShoppingPayment;
import com.chlitina.store.modules.cash.model.SolutionStoreCareCart;
import com.chlitina.store.modules.cash.model.SolutionStoreProductCart;
import com.chlitina.store.modules.cash.model.StoreCareCart;
import com.chlitina.store.modules.cash.model.StoreProductCart;
import com.chlitina.store.modules.cash.model.TimesCardPayment;
import com.chlitina.store.modules.cash.model.recharge.CardAllRecharge;
import com.chlitina.store.modules.cash.model.recharge.CardDurationRecharge;
import com.chlitina.store.modules.cash.model.recharge.CardProductRecharge;
import com.chlitina.store.modules.cash.model.recharge.CardTimesRecharge;
import com.chlitina.store.modules.cash.model.recharge.Recharge;
import com.chlitina.store.modules.cash.model.recharge.RechargeElementManager;
import com.chlitina.store.modules.cash.model.recharge.RehcargeHost;
import com.chlitina.store.modules.employee.dao.EmployeeDao;
import com.chlitina.store.modules.employee.dao.StoreBonusSettingCardDao;
import com.chlitina.store.modules.employee.dao.StoreBonusSettingCareDao;
import com.chlitina.store.modules.employee.dao.StoreBonusSettingProductDao;
import com.chlitina.store.modules.employee.entity.Employee;
import com.chlitina.store.modules.employee.entity.StoreBonusSettingCard;
import com.chlitina.store.modules.employee.entity.StoreBonusSettingCare;
import com.chlitina.store.modules.employee.entity.StoreBonusSettingProduct;
import com.chlitina.store.modules.sys.entity.Store;
import com.chlitina.store.modules.sys.utils.StoreUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

@Component
@Transactional(readOnly = true)
public class MemberService extends BaseService {
	@Autowired
	private StoreConsumeDebtDao storeConsumeDebtDao;
	@Autowired
	private StoreCardAllDao storeCardAllDao;
	@Autowired
	private StoreCardDurationDao storeCardDurationDao;
	@Autowired
	private StoreCardProductDao storeCardProductDao;
	@Autowired
	private StoreCardTimesDao storeCardTimesDao;
	@Autowired
	private StoreConsumeDao storeConsumeDao;
	@Autowired
	private StoreConsumeNewCardDao storeConsumeNewCardDao;
	@Autowired
	private StoreConsumeDoCareDao storeConsumeDoCareDao;
	@Autowired
	private StoreConsumeBuyProductDao storeConsumeBuyProductDao;
	@Autowired
	private StoreConsumeRechargeCardDao storeConsumeRechargeCardDao;
	@Autowired
	private StoreBonusSettingCardDao bonusSettingCardDao;
	@Autowired
	private StoreBonusSettingProductDao bonusSettingProductDao;
	@Autowired
	private StoreBonusSettingCareDao bonusSettingCareDao;
	@Autowired
	private StoreProductDao storeProductDao;
	@Autowired
	private CustomerEmployeeRelationshipService customerEmployeeRelationshipService;
	@Autowired
	private StoreConsumeService storeConsumeService;
	@Autowired
	private EmployeeDao employeeDao;
	@Autowired
	private StoreCareService storeCareService;

	public void loadingMemberInfo(Member member) {
		Long customer = member.getCustomer().getId();
		// reloading debt
		Long storeID = StoreUtils.getStore().getId();

		member.setStoreConsumeDebts(storeConsumeDebtDao.findListByCustomer(
				storeID, customer));
		member.setCustomerEmployeeRelationships(customerEmployeeRelationshipService
				.findByCustomer(customer));

		member.setEmployees(employeeDao.findListByStore(storeID,
				Employee.STATUS_WORKING));
		member.setInprogressCares(storeCareService
				.findCaresByCustomer(customer));
		if (!member.getEmployees().isEmpty()) {
			member.getNewCards().setEmployee(member.getEmployees().get(0));
		}

		// loading current cards
		loadingCurrentCards(member, storeID);

		member.init();

		// reloading card templates

		NewCards newCards = member.getNewCards();

		// loading history Consumes
		loadingMemeberHistoryConsumeInfo(member, storeID);

		member.updateMenuState();
		StoreUtils.setMember(member);
	}

	private void loadingMemeberHistoryConsumeInfo(Member member, Long storeID) {
		List<StoreConsume> consumes = storeConsumeService.findByCustomer(member
				.getCustomer().getId().longValue());
		member.setHistoryConsumes(consumes);
	}

	private void loadingCurrentCards(Member member, long storeID) {
		// loading current cards
		Cards currentCards = member.getCurrentCards();
		Long customer = member.getCustomer().getId();
		// CARD ALL
		currentCards.setAllCards(storeCardAllDao.findListByCustomer(storeID,
				customer));
		// CARD TIMES
		currentCards.setTimesCards(storeCardTimesDao.findListByCustomer(
				storeID, customer));

		// CARD DURATION
		currentCards.setDurationCards(storeCardDurationDao.findListByCustomer(
				storeID, customer));

		// CARD PRODUCT
		List<StoreCardProduct> productCards = storeCardProductDao
				.findListByCustomer(storeID, customer);
		// loading all data, with the deal there will be error for the lazy
		// loading
		for (StoreCardProduct storeCardProduct : productCards) {
			StoreCardTemplateProduct template = storeCardProduct.getTemplate();
			List<StoreCardTemplateProductDetail> productList = template
					.getProductList();
			productList.size();// can not be deleted
		}
		currentCards.setProductCards(productCards);
	}

	public StoreConsumeDebt findRefund(long consumeID) {
		Store store = StoreUtils.getStore();
		DetachedCriteria dc = storeConsumeDebtDao.createDetachedCriteria();
		dc.add(Restrictions.eq("store", store));
		dc.setFetchMode("debtConsume", FetchMode.JOIN);
		dc.setFetchMode("refundConsume", FetchMode.JOIN);
		dc.createAlias("refundConsume", "refundConsume");
		dc.createAlias("debtConsume", "debtConsume");
		dc.add(Restrictions.eq("refundConsume.id", consumeID));
		List<StoreConsumeDebt> find = storeConsumeDebtDao.find(dc);
		if (find.isEmpty()) {
			return null;
		}
		return find.get(0);
	}

	public StoreConsumeDebt findDebet(long consumeID) {
		Store store = StoreUtils.getStore();
		DetachedCriteria dc = storeConsumeDebtDao.createDetachedCriteria();
		dc.add(Restrictions.eq("store", store));
		dc.setFetchMode("debtConsume", FetchMode.JOIN);
		dc.setFetchMode("refundConsume", FetchMode.JOIN);
		dc.createAlias("refundConsume", "refundConsume");
		dc.createAlias("debtConsume", "debtConsume");
		dc.add(Restrictions.eq("debtConsume.id", consumeID));
		List<StoreConsumeDebt> find = storeConsumeDebtDao.find(dc);
		if (find.isEmpty()) {
			return null;
		}
		return find.get(0);
	}

	public MemberConsumeDetail loadMemberConsumeInfo(String id) {
		MemberConsumeDetail mcd = new MemberConsumeDetail();
		Long consumeId = Long.parseLong(id);
		StoreConsume storeConsume = storeConsumeDao.findOne(consumeId);
		StoreConsumeDebt refund = findRefund(consumeId);
		mcd.setStoreConsumeDebt(refund);
		mcd.setStoreConsume(storeConsume);
		List<StoreConsumeBuyProduct> storeConsumeBuyProductList = storeConsumeBuyProductDao
				.findListByConsume(consumeId);
		mcd.setStoreConsumeBuyProductList(storeConsumeBuyProductList);
		List<StoreConsumeNewCard> storeConsumeNewCardList = storeConsumeNewCardDao
				.findListByConsume(consumeId);
		mcd.setStoreConsumeNewCardList(storeConsumeNewCardList);
		List<StoreConsumeDoCare> storeConsumeDoCareList = storeConsumeDoCareDao
				.findListByConsume(consumeId);
		mcd.setStoreConsumeDoCareList(storeConsumeDoCareList);
		List<StoreConsumeRechargeCard> storeConsumeRechargeCardList = storeConsumeRechargeCardDao
				.findListByConsume(consumeId);
		mcd.setStoreConsumeRechargeCardList(storeConsumeRechargeCardList);
		return mcd;
	}

	public float getBonus(Store store, StoreProductCart cart) {
		int pType = cart.getStoreProduct().getProduct_type();
		int categoryType = 0;
		if (StoreProduct.TYPE_SYS == pType) {
			categoryType = cart.getStoreProduct().getProduct()
					.getProductCategory().getType();
		} else {
			categoryType = cart.getStoreProduct().getStoreSelfProduct()
					.getStoreSelfProductCategory().getId().intValue();
		}

		int payType = -1;
		ProductPayment payment = cart.getPayment();
		if (payment.getAllCardPaymentDetail() != null) {
			payType = StoreBonusSettingProduct.CARD_TYPE_ALL;
		} else if (payment.getProductCardPaymentDetail() != null) {
			payType = StoreBonusSettingProduct.CARD_TYPE_PRODUCT;
		} else {
			payType = StoreBonusSettingProduct.CARD_TYPE_MONEY;
		}
		long employeeID = cart.getEmployee().getId();
		List<StoreBonusSettingProduct> list = bonusSettingProductDao.list(store
				.getId().longValue(), employeeID, pType, categoryType, payType);
		if (list.isEmpty()) {
			return 0;
		}
		StoreBonusSettingProduct bonusSettingProduct = list.get(0);
		if (bonusSettingProduct.getBonus_type() == StoreBonusSettingProduct.BONUS_TYPE_FIXED) {
			return bonusSettingProduct.getFixed_money();
		} else {
			return bonusSettingProduct.getBonus_rate()
					* cart.getRealCostTotal();
		}
	}

	/**
	 * get reCharge bonus
	 * 
	 * @param store
	 * @param card
	 * @param recharge
	 * @return
	 */
	private float getBonus(Store store, Object card, Recharge recharge) {
		int cardType = 0;
		long templateId = 0;
		float realPayment = 0;
		if (card instanceof StoreCardAll) {
			cardType = StoreBonusSettingCard.CARD_TYPE_ALL;
			templateId = ((StoreCardAll) card).getTemplate().getId();
		} else if (card instanceof StoreCardTimes) {
			cardType = StoreBonusSettingCard.CARD_TYPE_TIMES;
			templateId = ((StoreCardTimes) card).getTemplate().getId();
		} else if (card instanceof StoreCardDuration) {
			cardType = StoreBonusSettingCard.CARD_TYPE_DURATION;
			templateId = ((StoreCardDuration) card).getTemplate().getId();
		} else if (card instanceof StoreCardProduct) {
			cardType = StoreBonusSettingCard.CARD_TYPE_PRODUCT;
			templateId = ((StoreCardProduct) card).getTemplate().getId();
		}
		List<StoreBonusSettingCard> list = bonusSettingCardDao.list(
				store.getId(), recharge.getEmployee().getId(), cardType,
				templateId);
		if (list.isEmpty()) {
			return 0;
		}
		realPayment = recharge.getMoney();
		StoreBonusSettingCard bonusSettingCard = list.get(0);
		if (bonusSettingCard.getBonus_type() == StoreBonusSettingCard.BONUS_TYPE_FIXED) {
			return bonusSettingCard.getFixed_money();
		} else {
			return bonusSettingCard.getBonus_rate() * realPayment;
		}
	}

	private float getBonus(Store store, CardCart cart) {
		Object card = cart.getCard();
		int cardType = 0;
		long templateId = 0;
		float realPayment = 0;
		if (card instanceof StoreCardAll) {
			cardType = StoreBonusSettingCard.CARD_TYPE_ALL;
			templateId = ((StoreCardAll) card).getTemplate().getId();
			realPayment = cart.getReal_cost();
		} else if (card instanceof StoreCardTimes) {
			cardType = StoreBonusSettingCard.CARD_TYPE_TIMES;
			templateId = ((StoreCardTimes) card).getTemplate().getId();
			realPayment = cart.getReal_cost();
		} else if (card instanceof StoreCardDuration) {
			cardType = StoreBonusSettingCard.CARD_TYPE_DURATION;
			templateId = ((StoreCardDuration) card).getTemplate().getId();
			realPayment = cart.getReal_cost();
		} else if (card instanceof StoreCardProduct) {
			cardType = StoreBonusSettingCard.CARD_TYPE_PRODUCT;
			templateId = ((StoreCardProduct) card).getTemplate().getId();
			realPayment = cart.getReal_cost();
		}
		List<StoreBonusSettingCard> list = bonusSettingCardDao
				.list(store.getId(), cart.getEmployee().getId(), cardType,
						templateId);
		if (list.isEmpty()) {
			return 0;
		}
		StoreBonusSettingCard bonusSettingCard = list.get(0);
		if (bonusSettingCard.getBonus_type() == StoreBonusSettingCard.BONUS_TYPE_FIXED) {
			return bonusSettingCard.getFixed_money();
		} else {
			return bonusSettingCard.getBonus_rate() * realPayment;
		}
	}

	private StoreConsume createConsume(Store store, Member member) {
		StoreConsume storeConsume = member.getShoppingCart().getStoreConsume();
		storeConsume.setConsume_Type(StoreConsume.TYPE_CONSUME_MEMBER);
		storeConsume.setCustomer(member.getCustomer());
		storeConsume.setMoney_To_Pay(member.getPayment().getTotal());// just
																		// cash
		return storeConsume;
	}

	private StoreConsumeNewCard createStoreConsumeNewCard(StoreConsume consume,
			StoreCardAll card, Employee employee, float realPrice, float bonus) {
		StoreConsumeNewCard storeConsumeNewCard = new StoreConsumeNewCard();
		storeConsumeNewCard.setEmployee(employee);
		storeConsumeNewCard.setBonus(bonus);
		storeConsumeNewCard.setCard_type(StoreConsumeNewCard.CARD_TYPE_ALL);
		storeConsumeNewCard.setReal_cost(realPrice);
		storeConsumeNewCard.setCard_id(card.getId());
		storeConsumeNewCard.setStoreConsume(consume);
		return storeConsumeNewCard;
	}

	/**
	 * 生成本次欠款
	 * 
	 * @param store
	 * @param consume
	 * @param member
	 * @return 返回 null,如果不存在欠款
	 */
	public StoreConsumeDebt createDebt(Store store, StoreConsume consume,
			Member member) {
		ShoppingPayment payment = member.getPayment();
		float debtMoney = payment.getDebt();
		if (debtMoney == 0) {
			return null;
		}
		StoreConsumeDebt debt = new StoreConsumeDebt();
		debt.setCustomer(member.getCustomer());
		debt.setDebtConsume(consume);
		debt.setStore(store);
		debt.setDebtMoney(debtMoney);
		return debt;
	}

	public String loadingMemberConsumeDetails(long consumeID) {

		return null;
	}

	@Transactional
	public StoreConsume payfor(Member member, MemberPayResult memberPayResult) {
		Store store = StoreUtils.getStore();
		NewCards newCards = member.getNewCards();
		StoreConsume consume = createConsume(store, member);
		// 优先保存本次消费单，因为其他的数据依赖于该消费单
		storeConsumeDao.save(consume);
		System.err.println("------Saved consume -----");
		StoreConsumeDebt lastDebt = member.getStoreConsumeDebt();

		if (lastDebt != null) {
			// 更新欠款单，记录本次还款消费单
			if (member.getRefundDebt() == lastDebt.getDebtMoney()) {
				lastDebt.setRefundConsume(consume);
				storeConsumeDebtDao.save(lastDebt);
				storeConsumeDebtDao.flush();
			} else {
				System.err.println("错误的还款金额，取消结算");
				// "错误的还款金额，取消结算", 从数据中删除对应的数据
				storeConsumeDao.delete(consume);
				storeConsumeDebtDao.flush();
				return null;
			}
		}

		// 生成本次欠款
		StoreConsumeDebt debt = createDebt(store, consume, member);
		if (debt != null) {
			storeConsumeDebtDao.save(debt);
		}
		// 保存新卡，并生成开发消费单
		saveNewCards(member, consume, newCards, store);
		System.err.println("------Saved new cards   -----");
		// 保存充值消费单
		saveRecharges(member, consume, store);
		System.err.println("------Saved new recharges-----");
		// 更新卡信息（耗卡，卡充值等）
		updateCards(member, consume, store);
		System.err.println("------updateCards-----");
		// 生成购买产品或护理消费单
		buyProductAndDoCare(member, consume, store, memberPayResult);
		if (!memberPayResult.getBuyProductFailed().isEmpty()) {
			//roll-back money for failed to buy 
			for (StoreProductCart storeProductCart : memberPayResult
					.getBuyProductFailed()) {
				ProductPayment payment = storeProductCart.getPayment();
				if (payment.getAllCardPaymentDetail() != null) {
					AllCardPaymentDetail allCardPaymentDetail = payment
							.getAllCardPaymentDetail();
					AllCardPayment cardPayment = allCardPaymentDetail
							.getCardPayment();
					float realCost = allCardPaymentDetail.getRealCost();
					StoreCardAll card = cardPayment.getCard();
					StoreCardAll findOne = storeCardAllDao
							.findOne(card.getId());
					findOne.setMoney(findOne.getMoney() + realCost);
					storeCardAllDao.save(findOne);
					storeCardAllDao.flush();
				} else if (payment.getProductCardPaymentDetail() != null) {
					ProductCardPaymentDetail productCardPaymentDetail = payment
							.getProductCardPaymentDetail();
					ProductCardPayment cardPayment = productCardPaymentDetail
							.getCardPayment();
					float realCost = cardPayment.getRealCost();
					StoreCardProduct findOne = storeCardProductDao
							.findOne(cardPayment.getCard().getId());
					findOne.setMoney(findOne.getMoney() + realCost);
					storeCardProductDao.save(findOne);
					storeCardProductDao.flush();
				} else {
					if (payment.getCash() > 0) {
						memberPayResult.addReturnCash(payment.getCash());
					}
				}
			}
		}
		System.err.println("------buyProductAndDoCare-----");
		// 生成增品消费单（产品消费单）
		saveGift(member, consume, store);
		System.err.println("------saveGift-----");
		return consume;
	}

	private void saveRecharges(Member member, StoreConsume consume, Store store) {
		RechargeElementManager rechargeEleMgr = member.getRechargeEleMgr();
		// CardAll
		for (RehcargeHost rehcargeHost : rechargeEleMgr.getRechargedCardAll()) {
			List<Recharge> recharges = rehcargeHost.getRecharges();
			StoreCardAll card = (StoreCardAll) ((CardPayment) rehcargeHost
					.getCard()).getCard();
			for (Recharge recharge : recharges) {
				StoreConsumeRechargeCard storeConsumeRechargeCard = createStoreConsumeRechargeCard(
						card, (CardAllRecharge) recharge, store);
				storeConsumeRechargeCard.setStoreConsume(consume);
				storeConsumeRechargeCardDao.save(storeConsumeRechargeCard);
			}
		}

		// CardProduct
		for (RehcargeHost rehcargeHost : rechargeEleMgr
				.getRechargedCardProduct()) {
			List<Recharge> recharges = rehcargeHost.getRecharges();
			StoreCardProduct card = (StoreCardProduct) ((CardPayment) rehcargeHost
					.getCard()).getCard();
			for (Recharge recharge : recharges) {
				StoreConsumeRechargeCard storeConsumeRechargeCard = createStoreConsumeRechargeCard(
						card, (CardProductRecharge) recharge, store);
				storeConsumeRechargeCard.setStoreConsume(consume);
				storeConsumeRechargeCardDao.save(storeConsumeRechargeCard);
			}
		}
		// CardDuration
		for (RehcargeHost rehcargeHost : rechargeEleMgr
				.getRechargedCardDuration()) {
			List<Recharge> recharges = rehcargeHost.getRecharges();
			StoreCardDuration card = (StoreCardDuration) ((CardPayment) rehcargeHost
					.getCard()).getCard();
			for (Recharge recharge : recharges) {
				StoreConsumeRechargeCard storeConsumeRechargeCard = createStoreConsumeRechargeCard(
						card, (CardDurationRecharge) recharge, store);
				storeConsumeRechargeCard.setStoreConsume(consume);
				storeConsumeRechargeCardDao.save(storeConsumeRechargeCard);
			}
		}
		for (RehcargeHost rehcargeHost : rechargeEleMgr.getRechargedCardTimes()) {
			List<Recharge> recharges = rehcargeHost.getRecharges();
			StoreCardTimes card = (StoreCardTimes) ((CardPayment) rehcargeHost
					.getCard()).getCard();
			for (Recharge recharge : recharges) {
				StoreConsumeRechargeCard storeConsumeRechargeCard = createStoreConsumeRechargeCard(
						card, (CardTimesRecharge) recharge, store);
				storeConsumeRechargeCard.setStoreConsume(consume);
				storeConsumeRechargeCardDao.save(storeConsumeRechargeCard);
			}
		}
	}

	// FIXME No Recharged Money and retail price
	private StoreConsumeRechargeCard createStoreConsumeRechargeCard(
			StoreCardTimes card, CardTimesRecharge recharge, Store store) {
		StoreConsumeRechargeCard rechargeCard = new StoreConsumeRechargeCard();
		rechargeCard.setCard_id(card.getId().longValue());
		rechargeCard.setCard_type(StoreConsumeRechargeCard.CARD_TYPE_TIMES);
		rechargeCard.setBonus(getBonus(store, card, recharge));
		rechargeCard.setEmployee(recharge.getEmployee());
		rechargeCard.setReal_cost(recharge.getMoney());
		rechargeCard.setRecharge_times(recharge.getTimes());
		return rechargeCard;
	}

	// FIXME No Recharged Money and retail price
	private StoreConsumeRechargeCard createStoreConsumeRechargeCard(
			StoreCardDuration card, CardDurationRecharge recharge, Store store) {
		StoreConsumeRechargeCard rechargeCard = new StoreConsumeRechargeCard();
		rechargeCard.setCard_id(card.getId().longValue());
		rechargeCard.setCard_type(StoreConsumeRechargeCard.CARD_TYPE_DURATION);
		rechargeCard.setBonus(getBonus(store, card, recharge));
		rechargeCard.setEmployee(recharge.getEmployee());
		rechargeCard.setReal_cost(recharge.getMoney());
		rechargeCard.setRecharge_duration(recharge.getDuration());
		rechargeCard.setRetail_price(recharge.getMoney());
		return rechargeCard;
	}

	private StoreConsumeRechargeCard createStoreConsumeRechargeCard(
			StoreCardProduct card, CardProductRecharge recharge, Store store) {
		StoreConsumeRechargeCard rechargeCard = new StoreConsumeRechargeCard();
		rechargeCard.setCard_id(card.getId().longValue());
		rechargeCard.setCard_type(StoreConsumeRechargeCard.CARD_TYPE_PRODUCT);
		rechargeCard.setBonus(getBonus(store, card, recharge));
		rechargeCard.setEmployee(recharge.getEmployee());
		rechargeCard.setReal_cost(recharge.getMoney());
		rechargeCard.setRecharge_money(recharge.getRechargeMoney());
		rechargeCard.setRetail_price(recharge.getRechargeMoney());
		return rechargeCard;
	}

	private StoreConsumeRechargeCard createStoreConsumeRechargeCard(
			StoreCardAll card, CardAllRecharge recharge, Store store) {
		StoreConsumeRechargeCard rechargeCard = new StoreConsumeRechargeCard();
		rechargeCard.setCard_id(card.getId().longValue());
		rechargeCard.setCard_type(StoreConsumeRechargeCard.CARD_TYPE_ALL);
		rechargeCard.setBonus(getBonus(store, card, recharge));
		rechargeCard.setEmployee(recharge.getEmployee());
		rechargeCard.setReal_cost(recharge.getMoney());
		rechargeCard.setRecharge_money(recharge.getRechargeMoney());
		rechargeCard.setRetail_price(recharge.getRechargeMoney());
		return rechargeCard;
	}

	private void saveGift(Member member, StoreConsume consume, Store store) {
		GiftCart giftCart = member.getGiftCart();
		for (StoreProductCart cart : giftCart.getStoreProducts()) {
			StoreConsumeBuyProduct p = createCosumeProductAsGift(store, cart);
			storeProductDao.save(cart.getStoreProduct());
			storeProductDao.flush();
			p.setStoreConsume(consume);
			storeConsumeBuyProductDao.save(p);
		}

		for (StoreProductCart cart : giftCart.getSystemProducts()) {
			StoreConsumeBuyProduct p = createCosumeProductAsGift(store, cart);
			storeProductDao.save(cart.getStoreProduct());
			storeProductDao.flush();
			p.setStoreConsume(consume);
			storeConsumeBuyProductDao.save(p);
		}

	}

	/**
	 * 卡充值，耗卡等
	 * 
	 * @param member
	 * @param consume
	 * @param store
	 */
	private void updateCards(Member member, StoreConsume consume, Store store) {
		List<AllCardPayment> allCardPayments = member.getAllCardPayments();
		for (AllCardPayment payment : allCardPayments) {
			float topay = payment.getMoney();
			float recharged = payment.getRechargeMoney();
			if (topay == 0 && recharged == 0) {
				continue;
			}
			StoreCardAll card = payment.getCard();
			StoreCardAll findOne = storeCardAllDao.findOne(card.getId());
			float money = findOne.getMoney();
			if (recharged + money - topay == payment.getCurrentMoney()) {
				card.setMoney(payment.getCurrentMoney());
			} else {
				System.err.println("StoreCardAll Payment state error");
			}
			storeCardAllDao.save(card);
			storeCardAllDao.flush();
		}

		List<ProductCardPayment> productCardPayments = member
				.getProductCardPayments();
		for (ProductCardPayment payment : productCardPayments) {
			float topay = payment.getMoney();
			float recharged = payment.getRechargeMoney();
			if (topay == 0 && recharged == 0) {
				continue;
			}
			StoreCardProduct card = payment.getCard();
			StoreCardProduct findOne = storeCardProductDao
					.findOne(card.getId());
			float money = findOne.getMoney();
			System.err.println(payment.getCurrentMoney());
			if (recharged + money - topay == payment.getCurrentMoney()) {
				card.setMoney(payment.getCurrentMoney());
			} else {
				System.err.println("StoreCardProduct Payment state error");
			}
			storeCardProductDao.save(card);
			storeCardProductDao.flush();
		}

		List<TimesCardPayment> timesCardPayments = member
				.getTimesCardPayments();
		for (TimesCardPayment payment : timesCardPayments) {
			int paidTimes = payment.getPaidTimes();
			int rechargeTimes = payment.getRechargeTimes();
			if (paidTimes == 0 && rechargeTimes == 0) {
				continue;
			}
			StoreCardTimes card = payment.getCard();
			StoreCardTimes findOne = storeCardTimesDao.findOne(card.getId());
			if (findOne.getRemainTimes() != card.getRemainTimes()) {
				System.err.println("StoreCardTimes Payment state error");
			}
			card.setRemainTimes(payment.getCurrentTimes());
			card.setCostPerTime(payment.getCostPertime());
			card.setRemainMoney(card.getRemainTimes() * card.getCostPerTime());
			storeCardTimesDao.save(card);
			storeCardTimesDao.flush();
		}

		List<DurationCardPayment> durationCardPayments = member
				.getDurationCardPayments();
		for (DurationCardPayment payment : durationCardPayments) {
			if (payment.getRechargedDuration() == 0) {
				continue;
			}
			StoreCardDuration card = payment.getCard();
			StoreCardDuration findOne = storeCardDurationDao.findOne(card
					.getId());
			if (!card.getBeginTime().toString()
					.equals(findOne.getBeginTime().toString())
					|| !card.getEndTime().toString()
							.equals(findOne.getEndTime().toString())) {
				System.err.println("StoreCardDuration Payment state error");
			}
			card.setEndTime(payment.getLimitTime());
			card.setLastRechargeDuration(payment.getRechargedDuration());
			storeCardDurationDao.save(card);
			storeCardDurationDao.flush();
		}

	}

	private void buyProductAndDoCare(Member member, StoreConsume consume,
			Store store, MemberPayResult payResult) {
		MemberShoppingCart shoppingCart = member.getShoppingCart();
		for (StoreProductCart cart : shoppingCart.getStoreProducts()) {
			StoreConsumeBuyProduct p = createCosumeProduct(store, cart);
			if (p == null) {
				payResult.getBuyProductFailed().add(cart);
				continue;
			}
			storeProductDao.save(cart.getStoreProduct());
			storeProductDao.flush();
			p.setStoreConsume(consume);
			storeConsumeBuyProductDao.save(p);
		}

		for (StoreProductCart cart : shoppingCart.getSystemProducts()) {
			StoreConsumeBuyProduct p = createCosumeProduct(store, cart);
			if (p == null) {
				payResult.getBuyProductFailed().add(cart);
				continue;
			}
			storeProductDao.save(cart.getStoreProduct());
			storeProductDao.flush();
			p.setStoreConsume(consume);
			storeConsumeBuyProductDao.save(p);
		}

		for (SolutionStoreProductCart cart : shoppingCart.getSolutionProducts()) {
			StoreConsumeBuyProduct p = createCosumeProduct(store, cart);
			if (p == null) {
				payResult.getBuyProductFailed().add(cart);
				System.err.println("failed to createCosumeProduct "
						+ cart.getPayment().getDescription());
				continue;
			}
			p.setRemark("方案id=" + cart.getSolutionID());
			storeProductDao.save(cart.getStoreProduct());
			storeProductDao.flush();
			p.setStoreConsume(consume);
			storeConsumeBuyProductDao.save(p);
		}

		for (StoreCareCart cart : shoppingCart.getSystemCares()) {
			StoreConsumeDoCare care = createCosumeCare(store, cart);
			care.setStoreConsume(consume);
			storeConsumeDoCareDao.save(care);
		}

		for (SolutionStoreCareCart cart : shoppingCart.getSolutionCares()) {
			StoreConsumeDoCare care = createCosumeCare(store, cart);
			care.setRemark("方案id=" + cart.getSolutionID());
			care.setStoreConsume(consume);
			storeConsumeDoCareDao.save(care);
		}

	}

	private StoreConsumeDoCare createCosumeCare(Store store, StoreCareCart cart) {
		StoreConsumeDoCare sp = new StoreConsumeDoCare();
		sp.setEmployee(cart.getEmployee());
		CarePayment payment = cart.getPayment();
		if (payment.getAllCardPaymentDetail() != null) {
			sp.setCard_id(payment.getAllCardPaymentDetail().getCardPayment()
					.getCard().getId().longValue());
			sp.setPayment_type(StoreConsumeDoCare.PAY_TYPE_All_CARD);
		} else if (payment.getDurattionCardPaymentDetail() != null) {
			sp.setCard_id(payment.getDurattionCardPaymentDetail()
					.getCardPayment().getCard().getId().longValue());
			sp.setPayment_type(StoreConsumeDoCare.PAY_TYPE_DURATION_CARD);
		} else if (payment.getTimesCardPaymentDetail() != null) {
			sp.setCard_id(payment.getTimesCardPaymentDetail().getCardPayment()
					.getCard().getId().longValue());
			sp.setPayment_type(StoreConsumeDoCare.PAY_TYPE_TIMES_CARD);
		} else {
			sp.setPayment_type(StoreConsumeDoCare.PAY_TYPE_CASH);
		}

		sp.setBonus(getBonus(store, cart));
		sp.setReal_cost(cart.getRealCostTotal());
		sp.setStoreCare(cart.getStoreCare());
		return sp;
	}

	public float getBonus(Store store, StoreCareCart cart) {
		long storeID = store.getId();
		long employeeID = cart.getEmployee().getId().longValue();
		long careId = cart.getStoreCare().getId().longValue();
		int payType = -1;
		CarePayment payment = cart.getPayment();
		if (payment.getAllCardPaymentDetail() != null) {
			payType = StoreBonusSettingCare.CARD_TYPE_All;
		} else if (payment.getDurattionCardPaymentDetail() != null) {
			payType = StoreBonusSettingCare.CARD_TYPE_DURATION;
		} else if (payment.getTimesCardPaymentDetail() != null) {
			payType = StoreBonusSettingCare.CARD_TYPE_TIMES;
		} else if (payment.getCash() > 0) {
			payType = StoreBonusSettingCare.CARD_TYPE_MONEY;
		}

		List<StoreBonusSettingCare> list = bonusSettingCareDao.list(storeID,
				employeeID, careId, payType);
		if (list.isEmpty()) {
			return 0;
		}
		StoreBonusSettingCare bonusSetting = list.get(0);
		if (bonusSetting.getBonus_type() == StoreBonusSettingCare.BONUS_TYPE_FIXED) {
			return bonusSetting.getFixed_money();
		} else {
			return bonusSetting.getBonus_rate() * cart.getRealCostTotal();
		}
	}

	/**
	 * 存储新开的卡，并生成开卡消费单
	 * 
	 * @param member
	 * @param consume
	 * @param newCards
	 * @param store
	 */
	private void saveNewCards(Member member, StoreConsume consume,
			NewCards newCards, Store store) {
		// save all cards
		List<CardCart> allCards = newCards.getAllCards();
		for (CardCart cart : allCards) {
			StoreCardAll card = (StoreCardAll) cart.getCard();
			card.setCustomer(member.getCustomer());
			storeCardAllDao.save(card);

			StoreConsumeNewCard newCard = createStoreConsumeNewCard(consume,
					card, cart.getEmployee(), cart.getReal_cost(),
					getBonus(store, cart));
			storeConsumeNewCardDao.save(newCard);

		}

		// save product cards
		List<CardCart> productCards = newCards.getProductCards();
		for (CardCart cart : productCards) {
			StoreCardProduct card = (StoreCardProduct) cart.getCard();
			card.setCustomer(member.getCustomer());
			storeCardProductDao.save(card);
			StoreConsumeNewCard newCard = createStoreConsumeNewCard(consume,
					card, cart.getEmployee(), cart.getReal_cost(),
					getBonus(store, cart));
			storeConsumeNewCardDao.save(newCard);
		}

		// save druration cards
		List<CardCart> durationCards = newCards.getDurationCards();
		for (CardCart cart : durationCards) {
			StoreCardDuration card = (StoreCardDuration) cart.getCard();
			card.setCustomer(member.getCustomer());
			storeCardDurationDao.save(card);
			StoreConsumeNewCard newCard = createStoreConsumeNewCard(consume,
					card, cart.getEmployee(), cart.getReal_cost(),
					getBonus(store, cart));
			storeConsumeNewCardDao.save(newCard);
		}

		// save care cards
		List<CardCart> timesCards = newCards.getTimesCards();
		for (CardCart cart : timesCards) {
			StoreCardTimes card = (StoreCardTimes) cart.getCard();
			card.setCustomer(member.getCustomer());
			storeCardTimesDao.save(card);

			StoreConsumeNewCard newCard = createStoreConsumeNewCard(consume,
					card, cart.getEmployee(), cart.getReal_cost(),
					getBonus(store, cart));
			storeConsumeNewCardDao.save(newCard);
		}
	}

	private StoreConsumeBuyProduct createCosumeProductAsGift(Store store,
			StoreProductCart cart) {
		StoreProduct storeProduct = storeProductDao.findOne(cart
				.getStoreProduct().getId());
		int left = storeProduct.getAmount() - cart.getCount();
		if (left < 0) {
			return null;
		}
		storeProduct.setAmount(left);
		cart.setStoreProduct(storeProduct);

		StoreConsumeBuyProduct sp = new StoreConsumeBuyProduct();
		sp.setAmount(cart.getCount());
		sp.setEmployee(cart.getEmployee());
		sp.setPayment_type(StoreConsumeBuyProduct.PAY_TYPE_GIFT);
		sp.setRetail_price(cart.getRetailPrice());
		sp.setBonus(0);
		sp.setReal_cost(0);
		sp.setReal_cost_total(0);
		sp.setStoreProduct(cart.getStoreProduct());
		return sp;
	}

	private StoreConsumeBuyProduct createCosumeProduct(Store store,
			StoreProductCart cart) {
		StoreProduct storeProduct = storeProductDao.findOne(cart
				.getStoreProduct().getId());
		int left = storeProduct.getAmount() - cart.getCount();
		if (left < 0) {
			System.err.println("库存不足");
			return null;
		}
		storeProduct.setAmount(left);
		cart.setStoreProduct(storeProduct);

		StoreConsumeBuyProduct sp = new StoreConsumeBuyProduct();
		sp.setAmount(cart.getCount());
		sp.setEmployee(cart.getEmployee());
		ProductPayment payment = cart.getPayment();
		if (payment.getAllCardPaymentDetail() != null) {
			sp.setCard_id(payment.getAllCardPaymentDetail().getCardPayment()
					.getCard().getId().longValue());
			sp.setPayment_type(StoreConsumeBuyProduct.PAY_TYPE_CARD_ALL);
		} else if (payment.getProductCardPaymentDetail() != null) {
			sp.setCard_id(payment.getProductCardPaymentDetail()
					.getCardPayment().getCard().getId().longValue());
			sp.setPayment_type(StoreConsumeBuyProduct.PAY_TYPE_CARD_PRODUCT);
		}
		sp.setRetail_price(cart.getRetailPrice());
		sp.setBonus(getBonus(store, cart));
		sp.setReal_cost(cart.getRealCost());
		sp.setReal_cost_total(cart.getRealCostTotal());
		sp.setStoreProduct(cart.getStoreProduct());
		return sp;
	}

	private StoreConsumeNewCard createStoreConsumeNewCard(StoreConsume consume,
			StoreCardProduct card, Employee employee, float real_cost,
			float bonus) {
		StoreConsumeNewCard storeConsumeNewCard = new StoreConsumeNewCard();
		storeConsumeNewCard.setEmployee(employee);
		storeConsumeNewCard.setBonus(bonus);
		storeConsumeNewCard.setCard_type(StoreConsumeNewCard.CARD_TYPE_PRODUCT);
		storeConsumeNewCard.setReal_cost(real_cost);
		storeConsumeNewCard.setCard_id(card.getId());
		storeConsumeNewCard.setStoreConsume(consume);
		return storeConsumeNewCard;
	}

	private StoreConsumeNewCard createStoreConsumeNewCard(StoreConsume consume,
			StoreCardDuration card, Employee employee, float real_cost,
			float bonus) {
		StoreConsumeNewCard storeConsumeNewCard = new StoreConsumeNewCard();
		storeConsumeNewCard.setEmployee(employee);
		storeConsumeNewCard.setBonus(bonus);
		storeConsumeNewCard
				.setCard_type(StoreConsumeNewCard.CARD_TYPE_DURATION);
		storeConsumeNewCard.setReal_cost(real_cost);
		storeConsumeNewCard.setCard_id(card.getId());
		storeConsumeNewCard.setStoreConsume(consume);
		return storeConsumeNewCard;
	}

	private StoreConsumeNewCard createStoreConsumeNewCard(StoreConsume consume,
			StoreCardTimes card, Employee employee, float real_cost, float bonus) {
		StoreConsumeNewCard storeConsumeNewCard = new StoreConsumeNewCard();
		storeConsumeNewCard.setEmployee(employee);
		storeConsumeNewCard.setBonus(bonus);
		storeConsumeNewCard.setCard_type(StoreConsumeNewCard.CARD_TYPE_TIMES);
		storeConsumeNewCard.setReal_cost(real_cost);
		storeConsumeNewCard.setCard_id(card.getId());
		storeConsumeNewCard.setStoreConsume(consume);
		return storeConsumeNewCard;
	}

	public String findMemberConsumeDetail(long consumeID) {
		HashMap<Object, Object> result = Maps.newHashMap();
		StoreConsume consume = storeConsumeDao.findOne(consumeID);
		if (consume != null) {
			result.put("number", consume.getConsume_Number());
			result.put("time", DateUtils.formatDate(consume.getConsume_Time(),
					"yyyy-MM-dd HH:mm:ss"));
			result.put("money", consume.getMoney_To_Pay());
			List<HashMap<Object, Object>> opencards = Lists.newArrayList();
			List<StoreConsumeNewCard> openCards = storeConsumeNewCardDao
					.findListByConsume(consumeID);
			HashMap<Object, Object> temp = null;
			for (StoreConsumeNewCard oc : openCards) {
				temp = Maps.newHashMap();
				long card_id = oc.getCard_id();
				int card_type = oc.getCard_type();
				String type = null;
				String cardname = null;
				String cardnumber = null;
				switch (card_type) {
				case StoreConsumeNewCard.CARD_TYPE_ALL:
					type = "综合卡";
					StoreCardAll cardAll = storeCardAllDao.findOne(card_id);
					cardname = cardAll.getTemplate().getName();
					cardnumber = cardAll.getCardNumber();
					break;
				case StoreConsumeNewCard.CARD_TYPE_PRODUCT:
					type = "产品卡";
					StoreCardProduct cardProduct = storeCardProductDao
							.findOne(card_id);
					cardname = cardProduct.getTemplate().getName();
					cardnumber = cardProduct.getCardNumber();
					break;
				case StoreConsumeNewCard.CARD_TYPE_DURATION:
					type = "时段卡";
					StoreCardDuration cardDuration = storeCardDurationDao
							.findOne(card_id);
					cardname = cardDuration.getTemplate().getName();
					cardnumber = cardDuration.getCardNumber();
					break;
				case StoreConsumeNewCard.CARD_TYPE_TIMES:
					type = "计次卡";
					StoreCardTimes cardTimes = storeCardTimesDao
							.findOne(card_id);
					cardname = cardTimes.getTemplate().getName();
					cardnumber = cardTimes.getCardNumber();
					break;
				}
				temp.put("type", type);
				temp.put("employee", oc.getEmployee().getName());
				temp.put("realCost", oc.getReal_cost());
				temp.put("payment", "现金");
				temp.put("cardname", cardname);
				temp.put("cardnumber", cardnumber);
				opencards.add(temp);
			}
			result.put("opencards", opencards);

			List<HashMap<Object, Object>> products = Lists.newArrayList();
			List<StoreConsumeBuyProduct> buyProducts = storeConsumeBuyProductDao
					.findListByConsume(consume.getId());
			StoreProduct storeProduct = null;
			for (StoreConsumeBuyProduct p : buyProducts) {
				temp = Maps.newHashMap();
				storeProduct = p.getStoreProduct();
				temp.put("name", StoreProductUtils.getName(storeProduct));
				temp.put("amount", p.getAmount());
				temp.put("retailPrice", p.getRetail_price());
				temp.put("spec", StoreProductUtils.getSpec(storeProduct));
				temp.put("employee", p.getEmployee().getName());
				temp.put("realCost", p.getReal_cost());
				temp.put("realCostTotal", p.getReal_cost_total());
				int payment_type = p.getPayment_type();
				String payment = null;
				switch (payment_type) {
				case StoreConsumeBuyProduct.PAY_TYPE_GIFT:
					payment = "赠品";
					break;
				case StoreConsumeBuyProduct.PAY_TYPE_CASH:
					payment = "现金";
					break;
				case StoreConsumeBuyProduct.PAY_TYPE_CARD_PRODUCT:
					StoreCardProduct cardProduct = storeCardProductDao
							.findOne(p.getCard_id());
					payment = "产品卡：" + cardProduct.getCardNumber();
					break;
				case StoreConsumeBuyProduct.PAY_TYPE_CARD_ALL:
					StoreCardAll cardAll = storeCardAllDao.findOne(p
							.getCard_id());
					payment = "综合卡：" + cardAll.getCardNumber();
					break;
				}
				temp.put("payment", payment);
				products.add(temp);
			}
			result.put("products", products);
			List<HashMap<Object, Object>> cares = Lists.newArrayList();
			List<StoreConsumeDoCare> doCares = storeConsumeDoCareDao
					.findListByConsume(consume.getId().longValue());
			StoreCare storeCare = null;
			for (StoreConsumeDoCare c : doCares) {
				temp = Maps.newHashMap();
				storeCare = c.getStoreCare();
				temp.put("name", StoreCareUtils.getName(storeCare));
				temp.put("retailPrice", c.getRetail_price());
				temp.put("duration", StoreCareUtils.getDuration(storeCare));
				temp.put("employee", c.getEmployee().getName());
				temp.put("realCost", c.getReal_cost());
				int payment_type = c.getPayment_type();
				String payment = null;
				switch (payment_type) {
				case StoreConsumeDoCare.PAY_TYPE_DURATION_CARD:
					StoreCardDuration cardDuration = storeCardDurationDao
							.findOne(c.getCard_id());
					payment = "时段卡：" + cardDuration.getCardNumber();
					break;
				case StoreConsumeDoCare.PAY_TYPE_TIMES_CARD:
					StoreCardTimes cardTimes = storeCardTimesDao.findOne(c
							.getCard_id());
					payment = "计次卡：" + cardTimes.getCardNumber();
					break;
				case StoreConsumeDoCare.PAY_TYPE_All_CARD:
					StoreCardAll cardAll = storeCardAllDao.findOne(c
							.getCard_id());
					payment = "综合卡：" + cardAll.getCardNumber();
					break;
				case StoreConsumeDoCare.PAY_TYPE_CASH:
					payment = "现金";
					break;
				}
				temp.put("payment", payment);
				cares.add(temp);
			}
			result.put("cares", cares);
			String json = JsonMapper.getInstance().toJson(result);
			System.err.println(json);
			return json;
		}
		return JsonMapper.getInstance().toJson(result);
	}
}
